from __future__ import annotations
import datetime
import logging
import typing
import google.protobuf.text_format as text_format

import coin.proto.coin_market_enums_pb2 as cm_enums_pb2
from coin.base.datetime_util import to_timestamp_int
from coin.proto.symbology_pb2 import ProductInfoProto
from cc.appcoin2.support.symbology.py_symbology import (
    PyCurrency,
    PyProduct as PybindProduct,
    PyProductHolder)


class PyProduct(object):
  def __init__(self, product: PybindProduct):
    self._product = product

  @classmethod
  def from_norm(cls, symbol: str, resolve_timestamp: int) -> PyProduct:
    product = PybindProduct.from_norm(symbol, resolve_timestamp)
    return cls(product)

  @classmethod
  def from_native(cls, symbol: str, resolve_timestamp: int) -> PyProduct:
    product = PybindProduct.from_native(symbol, resolve_timestamp)
    return cls(product)

  @property
  def product_holder(self) -> PyProductHolder:
    return self._product.product_holder

  @property
  def market_name(self) -> str:
    return self._product.market_name

  @property
  def exchange_name(self) -> str:
    return self._product.exchange_name

  @property
  def symbol(self) -> str:
    return self._product.symbol

  @property
  def native_symbol(self) -> str:
    return self._product.native_symbol

  @property
  def feed_native_symbol(self) -> str:
    return self._product.feed_native_symbol

  @property
  def order_native_symbol(self) -> str:
    return self._product.order_native_symbol

  @property
  def relative_norm(self) -> str:
    return self._product.relative_norm

  @property
  def absolute_norm(self) -> str:
    return self._product.absolute_norm

  @property
  def subscription_symbol(self) -> str:
    return self._product.subscription_symbol

  @property
  def native_subscription_symbol(self) -> str:
    return self._product.native_subscription_symbol

  @property
  def base(self) -> PyCurrency:
    return self._product.base

  @property
  def quote(self) -> PyCurrency:
    return self._product.quote

  @property
  def exchange(self) -> str:
    return self._product.exchange

  @property
  def product_type(self) -> str:
    return self._product.product_type

  @property
  def short_symbol(self) -> str:
    return self._product.short_symbol

  @property
  def full_symbol(self) -> str:
    return self._product.full_symbol

  @property
  def contract_type(self) -> typing.Optional[str]:
    try:
      contract_type = self._product.contract_type
    except Exception:
      logging.info('Fail to get contract type')
      contract_type = None
    return contract_type

  @property
  def expiry_str(self) -> typing.Optional[str]:
    return self._product.expiry_str

  @property
  def strike_price(self) -> typing.Optional[float]:
    strike_price = None
    try:
      strike_price = self._product.strike_price / self._product.strike_price_multiplier
      return strike_price
    except Exception:
      pass
    try:
      if self.pi_proto.product_type == cm_enums_pb2.OPTIONS:
        options_specifics = self.pi_proto.options_specifics
        if options_specifics.options_type in cm_enums_pb2.EUROPEAN_OPTIONS:
          specific = options_specifics.european_options_specific
          if specific.HasField('strike_price'):
            strike_price = specific.strike_price
        if options_specifics.options_type in cm_enums_pb2.AMERICAN_OPTIONS:
          specific = options_specifics.american_options_specific
          if specific.HasField('strike_price'):
            strike_price = specific.strike_price
    except Exception:
      pass
    return strike_price

  @property
  def option_side(self) -> int:
    return cm_enums_pb2.OptionsSide.Value(self._product.option_side)

  @property
  def is_perpetual(self) -> bool:
    return self._product.is_perpetual

  @property
  def is_immediate(self) -> bool:
    return self._product.is_immediate

  @property
  def pi_proto(self) -> ProductInfoProto:
    pi_string = self.product_holder.product_info.DebugString
    pi_proto = ProductInfoProto()
    return text_format.Parse(pi_string, pi_proto)

  def search_product_holder(self, fallback_days: int) -> PyProductHolder:
    return self._product.search_product_holder(fallback_days)


if __name__ == "__main__":
  dt = datetime.datetime(2023, 1, 1)
  product = PyProduct.from_norm(
      'Options:Otc:CCX-USDT.20250118.C.85679.1000000', to_timestamp_int(dt))
  print('market_name: ', product.market_name)
  print('exchange_name: ', product.exchange_name)
  print('symbol: ', product.symbol)
  print('native_symbol: ', product.native_symbol)
  print('feed_native_symbol: ', product.feed_native_symbol)
  print('order_native_symbol: ', product.order_native_symbol)
  print('relative_norm: ', product.relative_norm)
  print('absolute_norm: ', product.absolute_norm)
  print('subscription_symbol: ', product.subscription_symbol)
  print('native_subscription_symbol: ', product.native_subscription_symbol)
  print('exchange: ', product.exchange)
  print('product_type: ', product.product_type)
  print('short_symbol: ', product.short_symbol)
  print('full_symbol: ', product.full_symbol)
  print('contract_type: ', product.contract_type)
  print('expiry_str: ', product.expiry_str)
  print('is_perpetual: ', product.is_perpetual)
  print('is_immediate: ', product.is_immediate)
  print('strike_price: ', product.strike_price)
  print('pi_proto: ', product.pi_proto)
